package com.xqboss.framework.aspectj;


import com.alibaba.fastjson2.JSONObject;
import com.xqboss.common.core.domain.model.LoginUser;
import com.xqboss.common.utils.SecurityUtils;
import com.xqboss.common.utils.ip.IpUtils;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.UUID;

/**
 * @author Administrator
 */
@Aspect
@Component
@Order(1)
@Slf4j
public class LogPrintAspect {

    /**
     * 换行符
     */
    private static final String LINE_SEPARATOR = System.lineSeparator();

    private static final String REQUEST_ID = "REQUEST_ID";

    /**
     * 切入点 如果多个模块 controller替换为 *..*Controller
     */
    @Pointcut("execution(public * com.xqboss.*.controller..*.*(..))")
    public void logPrint() {

    }

    /**
     * 在切点之前织入
     *
     * @param joinPoint
     * @throws Throwable
     */
    @Before("logPrint()")
    public void doBefore(JoinPoint joinPoint) throws Throwable {
        try {
            // 开始打印请求日志
            ServletRequestAttributes attributes = getServletRequestAttributes();
            HttpServletRequest request = attributes.getRequest();
            String requestId = UUID.randomUUID().toString();
            attributes.setAttribute(REQUEST_ID, requestId, ServletRequestAttributes.SCOPE_REQUEST);
            JSONObject logJson = new JSONObject();
            logJson.put(REQUEST_ID, requestId);
            logJson.put("IP", IpUtils.getIpAddr(request));
            logJson.put("URL", request.getRequestURL().toString());
            logJson.put("START_TIME",  System.currentTimeMillis());
            log.info(logJson.toJSONString());
        } catch (Exception e) {
            log.error("前置日志异常记录：", e);
        }
    }

    /**
     * 环绕
     *
     * @param joinPoint
     * @return
     * @throws Throwable
     */
    @Around("logPrint()")
    public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable {
        JSONObject logJson = new JSONObject();
        Object result = null;
        long startTime = System.currentTimeMillis();
        try {
            ServletRequestAttributes attributes = getServletRequestAttributes();
            HttpServletRequest request = attributes.getRequest();
            String requestId = (String) attributes.getAttribute(REQUEST_ID, ServletRequestAttributes.SCOPE_REQUEST);
            LoginUser loginUser = SecurityUtils.getLoginUserOrNull();
            logJson.put(REQUEST_ID, requestId);
            logJson.put("IP", IpUtils.getIpAddr(request));
            logJson.put("USERID", loginUser == null ? "null" : loginUser.getUserId());
            logJson.put("URL", request.getRequestURL().toString());
            logJson.put("HTTP_METHOD", request.getMethod());
            logJson.put("APP_VERSION", request.getHeader("app-version"));
            logJson.put("APP_PLATFORM", request.getHeader("app-platform"));
            logJson.put("REQUEST_ARGS", getParams(joinPoint.getArgs()));
            logJson.put("START_TIME", startTime);
            result = joinPoint.proceed();
        } catch (Throwable throwable) {
            logJson.put("RUN_ERR", String.format("%s - %s", throwable.getMessage(), throwable.getStackTrace()[0].toString()));
            throw throwable;
        } finally {
            logJson.put("TIME_CONSUMING", System.currentTimeMillis() - startTime);
            log.info(logJson.toJSONString());
        }
        return result;
    }

    private String getParams(Object[] args) {
        StringBuilder params = new StringBuilder();
        if (args != null && args.length > 0) {
            for (Object arg : args) {
                if ((arg instanceof HttpServletResponse) || (arg instanceof HttpServletRequest)
                        || (arg instanceof MultipartFile) || (arg instanceof MultipartFile[])) {
                    continue;
                }
                try {
                    params.append(JSONObject.toJSONString(arg));
                } catch (Exception e) {
                    log.error(e.getMessage());
                }
            }
        }
        return params.toString();
    }

    private ServletRequestAttributes getServletRequestAttributes() {
        return (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
    }

}
